package main

import "fmt"

//               ↓此处表明为只写管道，声明之后内部不可读
func send(ch chan<- int,exitChan chan struct{}){
	fmt.Println("...")
}

//           ↓此处表明为只读管道，声明之后内部不可写
func recv(ch <- chan int,exitChan chan struct{}){
	fmt.Println("...")
}

func tests(){
	//协程panic 使用defer + recover 捕获异常
	defer func(){
		//捕获tests抛出的异常
		if err := recover(); err != nil{
			fmt.Printf("tests(), 发生异常",err)
		}
	}()

	var myMap map[int]string
	myMap[0] = "golang"
}


func main(){
	//管道可以什么为只读或者只写
	//1.在默认情况下，管道是双向的
	//var chan1 chan int //可读可写

	//2.声明为只写
	var chan2 chan<- int
	chan2 = make(chan int , 3)
	chan2<- 20
	//num := <- chan2 //error 只写不可读

	fmt.Print("chan2=",chan2)

	//3.声明为只读
	//var chan3 <- chan int
	//num2 := <- chan3
	////chan3 <- 30 //error 只读不可写
	//fmt.Println("num2",num2)

	//案例
	var ch chan int
	ch = make(chan int ,10)
	exitChan := make(chan struct{},2)
	go send(ch,exitChan)
	go recv(ch,exitChan)

	//1.定义一个管道 10个数据int
	intch := make(chan int,10)
	for i:=0;i<10;i++{
		intch <- i
	}

	//2.定义一个管道 5个数据string
	stringch := make(chan string ,5)
	for i:=0;i<5;i++{
		stringch <- "hello" + fmt.Sprintf("%d",i)
	}

	//可以使用select 方法解决不好确定什么时候关闭管道
	label:
	for{
		select{
			//注意：如果intch一直没有关闭，不会一直阻塞而deadlock 会自动到下一个case匹配
			case v:= <- intch :
				fmt.Printf("从intch 读取的数据%d\n",v)
			case v := <-stringch:
				fmt.Printf("从stringch读取的数据%s\n",v)
			default:
				fmt.Printf("都取不到数据。加自己的业务逻辑\n")
				//return //退出
				break label //退出标签
		}
	}

	go send(ch,exitChan)
	go tests()
	for i := 0;i < 10 ; i ++{
		fmt.Println("main() ok = ",i)
	}
}